package elastic.log.httpclient;

import com.alibaba.fastjson.JSON;

import elastic.log.SearchLog;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @param <T> 泛型
 * @author quxb
 * @version 1.0
 * @project 深圳OA
 * @package zhbg.oaxt.httpclient
 * @file SearchDao.java 创建时间:2018年7月23日下午3:51:07
 * @title 标题（要求能简洁地表达出类的功能和职责）
 * @description 描述（简要描述类的职责、实现方式、使用注意事项等）
 * @copyright Copyright (c) 2018 中国软件与技术服务股份有限公司
 * @company 中国软件与技术服务股份有限公司
 * @module 模块: 模块名称
 * @reviewer 审核人
 * @history 修订历史（历次修订内容、修订人、修订时间等）
 */
public class HttpProxy<T> {


    final private String max_total = "200";
    final private String max_per_route = "200";
    final private String request_timeout = "30000";
    final private String socket_timeout = "30000";
    final private String connect_timeout = "20000";
    
    /**
     * 检索服务 ip
     */
    public static String baseSearchUrl = "";

    /**
     * 日志
     */
    private static Logger log = LoggerFactory.getLogger(HttpProxy.class);

    /**
     * 单例
     */
    private static HttpProxy proxy = new HttpProxy();

    /**
     * 单例对象
     */
    private CloseableHttpClient httpClient;

    /**
     * 构造方法
     */
    private HttpProxy() {
        
        // 设置 SSL 全部信任
        SSLConnectionSocketFactory sslConnectionSocketFactory = null;
        try {
            final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] x509Certificates, String authType) throws CertificateException {
                    return true;
                }
            }).build();

            sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1", "TLSv1.2"},
                    null, NoopHostnameVerifier.INSTANCE);
        } catch (Exception e) {
            log.info("======初始化HttpClients连接池，SSL认证失败======", e);
        }
        final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", new PlainConnectionSocketFactory()).register("https", sslConnectionSocketFactory)
                .build();

        // 初始化连接池
        final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        connManager.setMaxTotal(Integer.parseInt(max_total));
        connManager.setDefaultMaxPerRoute(Integer.parseInt(max_per_route));

        final RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(Integer.parseInt(request_timeout))
                .setSocketTimeout(Integer.parseInt(socket_timeout)).setConnectTimeout(Integer.parseInt(connect_timeout))
                .build();

        httpClient = HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig)
                .build();
    }

    /**
     * @return 实例对象
     */
    public static HttpProxy getHttpProxy() {
        return proxy;
    }

    // /**
    // * 发起post请求
    // * @param url url
    // * @param param 参数
    // * @return 请求结果
    // */
    // public String httpPost(String url, Object param) throws
    // SwordBaseCheckedException {
    // final HttpPost httpPost = new HttpPost(url);
    //
    // // 设置参数
    // final String paramStr = JSON.toJSONString(param);
    // final StringEntity postEntity = new StringEntity(paramStr, "UTF-8");
    // postEntity.setContentType("application/json");
    // httpPost.setEntity(postEntity);
    //
    // // 发送请求
    // return getResultFromResponse(httpPost, url);
    // }

    /**
     * 发起http请求,针对查询
     *
     * @param url               url
     * @param nameValuePairList 参数
     * @return 请求结果
     */
    public Map httpPost(String url, List<NameValuePair> nameValuePairList) {
        final HttpPost httpPost = new HttpPost(url);

        // 设置参数
        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairList, StandardCharsets.UTF_8));

        return getResultFromResponseForSearch(httpPost, url);
    }

    /**
     * post请求，针对向es提交数据
     *
     * @param searchVo  参数
     * @param operation operation
     * @param url       url
     * @param id        id
     * @param index     index
     * @param retryNo   重试次数
     * @return 返回提交结果信息
     * @throws SwordBaseCheckedException
     */
    public boolean httpPost(String operation, String url, String index, String id, T searchVo, int retryNo) {
        final HttpPost httpPost = new HttpPost(url);

        // 设置参数
        final List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        final String value = JSON.toJSONString(searchVo);
        nameValuePairs.add(new BasicNameValuePair("index", index));
        nameValuePairs.add(new BasicNameValuePair("id", id));
        nameValuePairs.add(new BasicNameValuePair("value", value));
        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, StandardCharsets.UTF_8));

//        SearchLog.postLog(operation, index, id, value, null, retryNo, "szoa", "HttpProxy", true);
        return getResultFromResponseForSave(operation, url, index, id, searchVo, retryNo, httpPost);
    }

    /**
     * 解析http请求返回结果
     *
     * @param httpPost post请求
     * @param url      url
     * @return 返回结果
     */
    private Map getResultFromResponseForSearch(HttpPost httpPost, String url) {
        HttpResponse httpResponse = null;
        String result = "";

        // 发送请求
        try {
            httpResponse = httpClient.execute(httpPost);
            result = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            log.error("======发送http post请求失败，地址======" + url + "======错误信息======" + e.getMessage());
        }

        // 解析响应
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            final Map map = JSON.parseObject(result);
            final Object code = map.get("code");

            if (null != code && "0".equals(code.toString())) {
                return (Map) map.get("data");
            } else {
                log.error("======发送http post请求失败，地址======" + url + "======错误信息======" + (map.get("message")==null?"httpMsg:"+map.get("msg"):"esMessage："+map.get("message")));
            }
        } else {
            log.error("======发送http post请求失败，地址======" + url + "======错误信息======" + result);
        }
        
        return null;
    }

    /**
     * 解析http请求返回结果
     *
     * @param operation operation
     * @param url       url
     * @param index     index
     * @param id        id
     * @param searchVo  searchVo
     * @param retryNo   重试次数
     * @param httpPost  post请求
     * @return 返回结果
     */
    private boolean getResultFromResponseForSave(String operation, String url, String index, String id, T searchVo, int retryNo, HttpPost httpPost) {
        HttpResponse httpResponse = null;
        String result = "";

        // 发送请求
        try {
            httpResponse = httpClient.execute(httpPost);
            result = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            //return handleError(operation, url, index, id, searchVo, retryNo, e.getMessage());
        }

        // 解析响应
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            final Map map = JSON.parseObject(result);
            final Object code = map.get("code");

            if (null == code || !"0".equals(code.toString())) {
                //return handleError(operation, url, index, id, searchVo, retryNo, (map.get("message")==null?"httpMsg："+map.get("msg"):"esMessage："+map.get("message")).toString());
            }
        } else {
            //return handleError(operation, url, index, id, searchVo, retryNo, result);
        }

        return true;
    }

    public boolean httpPostElk(String url, String searchVo, boolean bulk) {
        final HttpPost httpPost = new HttpPost(url);

        try {
            // 设置参数
            final StringEntity entity = new StringEntity(searchVo, "utf-8");
            httpPost.setEntity(entity);
            httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");
//            httpPost.setHeader("Connection", "keep-alive");
//            httpPost.setHeader("X-Requested-With", "XMLHttpRequest");

            // 发送请求
            HttpResponse httpResponse = null;
            httpResponse = httpClient.execute(httpPost);
            final String result = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);

            // 解析响应
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                final Map map = JSON.parseObject(result);
                final boolean errors = Boolean.valueOf(String.valueOf(map.get("errors")));

                return !errors;
            } else {
                log.error("======发送http post请求失败，地址======" + url + "======错误信息======" + result);
            }
        } catch (IOException e) {
            log.error("======发送http post请求失败，地址======" + url + "======错误信息======" + e.getMessage());
        }
        finally{
       //     httpPost.releaseConnection();
            //httpClient.getConnectionManager().closeIdleConnections(0, null);
        }
        
        return false;
    }
    
    public boolean httpGetElk(String url) {
        final String requestContentType = "application/json; charset=UTF-8";
        final HttpGet httpGet = new HttpGet(url);

        try {
            // 发送请求
            HttpResponse httpResponse = null;
            httpResponse = httpClient.execute(httpGet);
            final String result = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);

            // 解析响应
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                final Map map = JSON.parseObject(result);
                final boolean errors = Boolean.valueOf(String.valueOf(map.get("errors")));

                return !errors;
            } else {
                log.error("======发送http post请求失败，地址======" + url + "======错误信息======" + result);
            }
        } catch (IOException e) {
            log.error("======发送http post请求失败，地址======" + url + "======错误信息======" + e.getMessage());
        }
        finally{
      //      httpGet.releaseConnection();
            //httpClient.getConnectionManager().closeIdleConnections(0, null);
        }
        
        return false;
    }
}
